package com.aliwo.controller;

import com.aliwo.response.ResultResponse;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.Duration;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 分布式锁.
 *
 * @author Xu Yayuan
 * @date 2023-04-17
 */
@RestController("/api/v1/dcs")
public class DcsLockController {

    private StringRedisTemplate redisTemplate;

    /**
     * 获取图形验证码
     *
     * @param couponId couponId
     * @author xuyy
     */
    @GetMapping(value = "lockScript")
    public ResultResponse lockByLuaScript(@RequestParam String couponId) {
        String lockKey = "lock:coupon:" + couponId;
        String uuid = UUID.randomUUID().toString();
        this.lock(lockKey, uuid);
        return ResultResponse.buildSuccess();
    }

    /**
     * @param lockKey redisLockKey
     * @param uuid    value
     */
    private void lock(String lockKey, String uuid) {
        // lua脚本
        String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        Boolean nativeLock = redisTemplate.opsForValue().setIfAbsent(lockKey, uuid, Duration.ofSeconds(30));
        System.out.println(uuid + "加锁状态:" + nativeLock);
        // 加锁成功
        if (nativeLock) {
            try {
                //TODO 做相关业务逻辑
                TimeUnit.SECONDS.sleep(10L);
            } catch (InterruptedException ignored) {

            } finally {
                //解锁
                Long result = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Collections.singletonList(lockKey), uuid);
                System.out.println("解锁状态:" + result);
            }
        } else {
            // 加锁失败 休眠2秒
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 进行自旋调用
            this.lock(lockKey, uuid);
        }
    }
}
